package com.itheima.stock.service.impl;

import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.gson.Gson;
import com.itheima.stock.common.domain.*;
import com.itheima.stock.config.vo.PageResult;
import com.itheima.stock.config.vo.StockInfoConfig;
import com.itheima.stock.mapper.StockBlockRtInfoMapper;
import com.itheima.stock.mapper.StockBusinessMapper;
import com.itheima.stock.mapper.StockMarketIndexInfoMapper;
import com.itheima.stock.mapper.StockRtInfoMapper;
import com.itheima.stock.pojo.StockBusiness;
import com.itheima.stock.service.StockService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.vo.resp.R;
import com.itheima.stock.vo.resp.ResponseCode;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Service("stockService")
public class StockServiceImpl implements StockService {

    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    @Override
    public List<StockBusiness> findAll() {
        return stockBusinessMapper.findAll();
    }

    /*
     * 获取最新的A股大盘信息,如果不在股票交易日,则显示最新的的交易数据信息
     * */
    @Override
    public R<List<InnerMarketDomain>> getNewMarketInfo() {
        //1.获取国内A股大盘的id集合
        List<String> inners = stockInfoConfig.getInner();
        //2.获取最近股票交易日期
        DateTime lastDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //3.转java中的Date
        Date lastDate = lastDateTime.toDate();
        //TODO mock测试数据,后期通过第三方接口动态获取实时数据

        lastDate = DateTime.parse("2022-01-03 11:15:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //4.将获取的java Date传入接口
        List<InnerMarketDomain> list = stockMarketIndexInfoMapper.getMarkInfo(inners, lastDate);
        //5.返回查询结果
        return R.ok(list);
    }

    /*
     * 需求说明: 沪深两市板块分时行情数据查询，以交易时间和交易总金额降序查询，取前10条数据
     */
    @Override
    public R<List<StockBlockDomain>> sectorAllLimit() {
        //1.调用mapper接口获取数据 TODO 优化 避免全表查询 根据时间范围查询，提高查询效率
        List<StockBlockDomain> infos = stockBlockRtInfoMapper.sectorAllLimit();
        //2.组装数据
        if (CollectionUtils.isEmpty(infos)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA.getMessage());
        }
        return R.ok(infos);
    }

    //统计沪深两市个股最新交易数据,并按涨幅降序排列查询前十条信息
    @Override
    public R<List<StockUpdownDomain>> stockIncreaseLimit() {
        //1.获取最近最新的股票有效交易时间地点(分钟-**)
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO mock 测试数据
        lastDate = DateTime.parse("2021-12-30 09:42:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.调用mapper 查询
        List<StockUpdownDomain> list = stockRtInfoMapper.getStockRtInfoLimit(lastDate);
        //判断集合状态
        if (CollectionUtils.isEmpty(list)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA.getMessage());
        }
        return R.ok(list);
    }

    /*
     * page 当前页 pageSize 每页大小
     * 分页查询股票交易数据,按照日期和涨幅降序排序
     * */
    @Override
    public R<PageResult<StockUpdownDomain>> getStockInfo4Page(Integer page, Integer pageSize) {
        //1.设置分页参数
        PageHelper.startPage(page, pageSize);
        //2.查询
        List<StockUpdownDomain> pages = stockRtInfoMapper.getStockInfo4All();
        if (CollectionUtils.isEmpty(pages)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA.getMessage());
        }
        //3.组装PageInfo对象,封装了一切分页信息
        PageInfo<StockUpdownDomain> pageInfo = new PageInfo<>(pages);
        //4.转换成自定义的分页对象
        PageResult<StockUpdownDomain> pageResult = new PageResult<StockUpdownDomain>(pageInfo);

        return R.ok(pageResult);
    }

    /*
     * 统计T日(最近最新一次股票交易日)涨停和跌停分数统计
     * */
    @Override
    public R<Map> getSotckUpdownCount() {
        //1.使用工具类获取最近交易日的开盘时间和收盘时间
        //获取有效时间点
        DateTime avableTimePoint = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //根据有效时间点获取对应日期的开票和收盘日期
        Date openTime = DateTimeUtil.getOpenDate(avableTimePoint).toDate();
        Date closeTime = DateTimeUtil.getCloseDate(avableTimePoint).toDate();
        //TODO mock数据
        openTime = DateTime.parse("2021-12-19 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        closeTime = DateTime.parse("2021-12-19 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.查询涨停的统计数据
        List<Map> upList = stockRtInfoMapper.getStockUpDownCount(openTime, closeTime, 1);
        //3.查询跌停的数据
        List<Map> downList = stockRtInfoMapper.getStockUpDownCount(openTime, closeTime, 1);
        //4.组装map:将涨停和跌停的数据组装进map中
        HashMap<String, List> map = new HashMap<>();
        map.put("upList", upList);
        map.put("downList", downList);
        //5.返回结果
        return R.ok(map);
    }

    /*
     * 将指定页的股票数据导出到excel表下
     * response
     * page  当前页 pageSize 每页大小
     */
    @Override
    public void stockExport(HttpServletResponse response, Integer page, Integer pageSize) throws IOException {
        //1.设置响应数据的类型:excel
        response.setContentType("application/vnd.ms-excel");
        //2.设置响应数据的编码格式
        response.setCharacterEncoding("utf-8");
        //3.设置默认的文件名称
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("stockRt", "UTF-8");
        //设置默认文件名称
        response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xlsx");
        //1.分页查询股票数据
        PageHelper.startPage(page, pageSize);
        List<StockUpdownDomain> pages = stockRtInfoMapper.getStockInfo4All();
        if (CollectionUtils.isEmpty(pages)) {
            R<String> error = R.error(ResponseCode.NO_RESPONSE_DATA.getMessage());
            //将错误信息转化成json字符串响应给前端
            String josnData = new Gson().toJson(error);
            //响应给前端错误数据
            response.getWriter().write(josnData);
            //终止当前程序
            return;
        }
        //将List<StockUpdownDomain>转化成List<StockExcelDomain>
        List<StockExcelDomain> domains = pages.stream().map(item -> {
            StockExcelDomain domain = new StockExcelDomain();
            BeanUtils.copyProperties(item, domain);
            return domain;
        }).collect(Collectors.toList());
        //数据导出
        EasyExcel.write(response.getOutputStream(), StockExcelDomain.class).sheet("股票数据").doWrite(domains);

    }

    /*
     * 功能描述：统计国内A股大盘T日和T-1日成交量对比功能（成交量为沪市和深市成交量之和）
     *      T-1日保证与T日时间线对其:
     *    如果当前时间点不在有效的股票交易日下,则将距离当前最近的一个时间点作为T日时间的查询:
     */
    @Override
    public R<Map> getStockTradeVol4Comparison() {
        //1.获取T日不T-1日的开始时间和结束时间
        //1.1获取最近股票有效交易时问点--T日时问范用
        DateTime lastDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        DateTime openDateTime = DateTimeUtil.getOpenDate(lastDateTime);
        //转化成java中Date,这样jdbc默认识别
        Date startTimeT = openDateTime.toDate();
        Date endTime4T = lastDateTime.toDate();
        //TODO mock测试数据
        startTimeT = DateTime.parse("2022-01-03 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        endTime4T = DateTime.parse("2022-01-03 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //1.2获取T-1日的区问范围
        //获取lastDateTime 的上个股票有效交易日
        DateTime preLastDateTime = DateTimeUtil.getPreviousTradingDay(lastDateTime);
        DateTime pre0penDateTime = DateTimeUtil.getOpenDate(preLastDateTime);
        //转化成java中fDate, 这样jdbc默认识别
        Date startTime4PreT = pre0penDateTime.toDate();
        Date endTime4PreT = preLastDateTime.toDate();
        //TODO mock测试数据
        startTime4PreT = DateTime.parse("2022-01-02 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        endTime4PreT = DateTime.parse("2022-01-02 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.获取上证和深证的配置的大盘id
        //2.1 获取大盘的id集合
        List<String> markedIds = stockInfoConfig.getInner();
        //3.分别查询T日利T-1日的交易量数据，得到两个集合
        //3.1查询T日大盘交易统计数据
        List<Map> data4T = stockMarketIndexInfoMapper.getStockTradeVol(markedIds, startTimeT, endTime4T);
        //3.2查询T-1日大盘交易统计数据
        List<Map> data4PreT = stockMarketIndexInfoMapper.getStockTradeVol(markedIds, startTime4PreT, endTime4PreT);
        //4.组装响应数据
        HashMap<String, List> info = new HashMap<>();
        info.put("volList", data4T);
        info.put("yesVolList", data4PreT);
        //5.返回数据
        return R.ok(info);
    }

    /*
     * 统计计当前时问下（精确到分钟），股票在各个冰阳区问的数量
     * 如果当前不在股票有效时间内，则以最近最新的一个有效股票交易日作为查询时间点展示;
     * */
    @Override
    public R<Map> getStockUpDownRegion() {
        //1.获取股祟最新交易时间
        DateTime dateTime4Stock = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date lastDate = dateTime4Stock.toDate();
        //TODO mock测试数据
        lastDate = DateTime.parse("2021-12-30 09:42:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.插入mapper接口获取统计数据(无序)
        List<Map> infos = stockRtInfoMapper.getStockUpDownRegion(lastDate);
        if (CollectionUtils.isEmpty(infos)) {
            infos = new ArrayList<>();
        }
        //保证涨幅区间按照从小到大排序, 且对于没有数据的涨幅区间默认为0
        //思路:只需按照顺序循环遍历自定的涨幅区间集合,然后获取对应map,就可保证各个map对象的顺序
        List<String> upDownRangeList = stockInfoConfig.getUpDownRange();
        //通过stream流map映射和过滤完成转换
        List<Map> finalInfos = infos;
        List<Map> newMaps = upDownRangeList.stream().map(item -> {
            Optional<Map> optional = finalInfos.stream().filter(map -> map.get("title").equals(item)).findFirst();
            Map tmp = null;
            //判断是否有map
            if (optional.isPresent()) {
                tmp = optional.get();
            } else {
                tmp = new HashMap();
                tmp.put("title", item);
                tmp.put("count", 0);
            }
            return tmp;
        }).collect(Collectors.toList());
        /*//构建新的集合 方式一普通循环
        List<Map> newMaps = new ArrayList<>();
        for (String item : upDownRangeList) {
            //循环查询的infos集合,找到item对应的map即可
            Map tmp = null;
            for (Map info : infos) {
                if (info.get("title").equals(item)) {
                    tmp = info;
                }
            }
            if (tmp == null) {
                tmp = new HashMap<>();
                tmp.put("title", item);
                tmp.put("count", 0);
            }
            newMaps.add(tmp);
        }*/
        //3.组装数据，并啊应
        HashMap<String, Object> data = new HashMap<>();
        //获取日期期格式,是为了前端友好展示
        String stringDateTime = dateTime4Stock.toString(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss "));
        data.put("time", stringDateTime);
        data.put("infos", newMaps);
        return R.ok(data);
    }

    /*
     *查询个股的分时行情数据，也就是统计指定股票T日每分钟的交易数据
     * stockCode : 股票的编码(code)
     */
    @Override
    public R<List<Stock4MinuteDomain>> stockCreenTimeSharing(String stockCode) {
        //1.获取最近最新的交易时间点和对应的开盘日期//1.1获取最近有效时间点
        DateTime lastDate4Stock = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endTime = lastDate4Stock.toDate();
        //TODO mock测试数据
        endTime = DateTime.parse("2021-12-30 14:47:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        ////1.2获取最近有效时间点对应的开盘日期
        DateTime openDateTime = DateTimeUtil.getOpenDate(lastDate4Stock);
        Date startTime = openDateTime.toDate();
        //TODO  mock测试数据
        startTime = DateTime.parse("2021-12-30 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        ////2.根据股票code和日期范围查询
        List<Stock4MinuteDomain> list = stockRtInfoMapper.getStockInfoByCodeAndDate(stockCode, startTime, endTime);
        //判断非空处理
        if (CollectionUtils.isEmpty(list)) {
            list = new ArrayList<>();
        }
        return R.ok(list);
    }

    /*
     * 功能描述:个股日K数据查询,可以根时间区问查询数日的K线数据
     *       默认查询历史20天的数据;
     *   注意:如果当大盘尚未收盘，则以最新的交易价格作为收盘价格
     * */
    @Override
    public R<List<Stock4EvrDayDomain>> stockScreenDkLine(String code) {
        //1.获取查询的日期范围
        //1.1获取截止时间
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endTime = endDateTime.toDate();
        //TODO mock测试数据
        endTime = DateTime.parse("2022-01-07 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //1.2获取开始时间
        DateTime startDateTime = endDateTime.minusDays(10);
        Date startTime = startDateTime.toDate();
        //TODO mock测试数据
        startTime = DateTime.parse("2022-01-01 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.调用mapper接口获取查询的集合信息
        List<Stock4EvrDayDomain> data = stockRtInfoMapper.getStockInfoEvrDay(code, startTime, endTime);
        if (CollectionUtils.isEmpty(data)) {
            data = new ArrayList<>();
        }
        //3.组装数据，响应
        return R.ok(data);
    }

}
